//Linux Headers
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <time.h>
#include <semaphore.h>
#include <errno.h>

//WiringPI Headers
#include <wiringPi.h>
#include <wiringPiI2C.h>
#include <wiringSerial.h>

//Xively Headers
#include "libxively/xively.h"
#include "libxively/xi_helpers.h"
#include "libxively/xi_err.h"


#define LED 7//8
#define sSDA 15
#define sSCL 16

sem_t Semaphore;

int32_t Cnt_sSDA=0;
int32_t Cnt_sSCL=0;
unsigned int ArduinoData=0;

void digitalWriteToggle(unsigned char PinNo)
{
	if(digitalRead(PinNo)){
		digitalWrite (PinNo, 0) ;	
	}
	else{
		digitalWrite (PinNo, 1) ;	
	}
}


void* Thread1(void *data)
{
//	(void)piHiPri (10) ;
	for (;;)
	{
		//printf("1"); fflush(stdout);
		digitalWriteToggle(LED);
		usleep(500*1000); //500ms 동안 대기
	}
}

void* Thread2(void *data)
{
//	(void)piHiPri (10) ;
	for (;;)
	{
		//printf("2"); fflush(stdout);
		sem_post(&Semaphore);
		sleep(5);
	}
}


#define xi_api_key	"MNC8cY50oQDZ6ObQ8vdbmmOg01il4KwDWqhaArCURXh8NTAk"
#define xi_feed_id	1989666334
#define xi_datastream_id0 "led"
#define xi_datastream_id1 "light"
#define xi_datastream_id2 "Test"
#define xi_datastream_id3 "Echo"

void* Thread3(void *data)
{
	volatile unsigned char value=0;
	
	// create the xi library context
	xi_context_t* xi_context = xi_create_context(XI_HTTP, xi_api_key, xi_feed_id );
	
	// check if everything works
	if( xi_context == 0 )
	{
		//printf("Error\n");
		//return -1;
	}


	xi_datapoint_t datapoint;
	for (;;)
	{
		sem_wait(&Semaphore);
		xi_set_value_i32( &datapoint, (int32_t)value );
		xi_datastream_update( xi_context, xi_feed_id, xi_datastream_id2, &datapoint);
		value++;
	}
	
	// destroy the context cause we don't need it anymore
	xi_delete_context( xi_context );
}


void* __Thread3(void *data)
{
	volatile unsigned char value=0;
	volatile unsigned char Echo=0;
	
	// create the xi library context
	xi_context_t* xi_context = xi_create_context(XI_HTTP, xi_api_key, xi_feed_id );
	
	// check if everything works
	if( xi_context == 0 )
	{
		//printf("Error\n");
		//return -1;
	}

	//---------------------------------------------- Datastream Get (OneShot when power-up)
	xi_datapoint_t Get_datapoint;
	xi_datastream_get( xi_context , xi_feed_id, xi_datastream_id2, &Get_datapoint );
//	printf( "timestamp = %ld.%ld, value = %d\n", Get_datapoint.timestamp.timestamp, Get_datapoint.timestamp.micro, Get_datapoint.value.i32_value );
	value=(unsigned char)Get_datapoint.value.i32_value;

	xi_datapoint_t* datapoint;
	xi_feed_t feed;
    	memset( &feed, 0, sizeof( xi_feed_t ));
	feed.feed_id = xi_feed_id;
	feed.datastream_count = 4;
	for (;;)
	{
		sem_wait(&Semaphore);

		//---------------------------------------------- Datastream Get
		Echo=0;
		xi_datastream_get( xi_context , xi_feed_id, xi_datastream_id3, &Get_datapoint );
		//printf( "timestamp = %ld.%ld, value = %d\n", Get_datapoint.timestamp.timestamp, Get_datapoint.timestamp.micro, Get_datapoint.value.i32_value );
		Echo=(unsigned char)Get_datapoint.value.i32_value;
		Echo++;

		//---------------------------------------------- Feed Update
		//Datastream0
		feed.datastreams[0].datapoint_count=1;
		xi_str_copy_untiln(feed.datastreams[0].datastream_id, sizeof(xi_datastream_id0), xi_datastream_id0, '\0' );
		datapoint = (xi_datapoint_t*)&feed.datastreams[0].datapoints;
		xi_set_value_i32(datapoint, ArduinoData);
		//Datastream1
		feed.datastreams[1].datapoint_count=1;
		xi_str_copy_untiln(feed.datastreams[1].datastream_id, sizeof(xi_datastream_id1), xi_datastream_id1, '\0' );
		datapoint = (xi_datapoint_t*)&feed.datastreams[1].datapoints;
		xi_set_value_i32(datapoint, 0xff-value);
		//Datastream2
		feed.datastreams[2].datapoint_count=1;
		xi_str_copy_untiln(feed.datastreams[2].datastream_id, sizeof(xi_datastream_id2), xi_datastream_id2, '\0' );
		datapoint = (xi_datapoint_t*)&feed.datastreams[2].datapoints;
		xi_set_value_i32(datapoint, value);
		//Datastream3
		feed.datastreams[3].datapoint_count=1;
		xi_str_copy_untiln(feed.datastreams[3].datastream_id, sizeof(xi_datastream_id3), xi_datastream_id3, '\0' );
		datapoint = (xi_datapoint_t*)&feed.datastreams[3].datapoints;
		xi_set_value_i32(datapoint, value);
		//Update
		xi_feed_update(xi_context, &feed);
		//printf( "err: %d - %s\n", ( int ) xi_get_last_error(), xi_get_error_string( xi_get_last_error() ) ); fflush(stdout);

		
		
		value++;
	}
	
	// destroy the context cause we don't need it anymore
	xi_delete_context( xi_context );
}



void* _Thread3(void *data)
{
//	(void)piHiPri (10) ;
	volatile unsigned char value=77;
	
	// create the xi library context
	xi_context_t* xi_context = xi_create_context(XI_HTTP, xi_api_key, xi_feed_id );
	
	// check if everything works
	if( xi_context == 0 )
	{
		//printf("Error\n");
		//return -1;
	}
	
	xi_datapoint_t* datapoint;
	xi_feed_t feed;
    	memset( &feed, 0, sizeof( xi_feed_t ));
	feed.feed_id = xi_feed_id;
	feed.datastream_count = 2;
	for (;;)
	{
		sem_wait(&Semaphore);

		//---------------------------------------------- Feed Update
		//Datastream0
		feed.datastreams[0].datapoint_count=1;
		xi_str_copy_untiln(feed.datastreams[0].datastream_id, sizeof(xi_datastream_id0), xi_datastream_id0, '\0' );
		datapoint = (xi_datapoint_t*)&feed.datastreams[0].datapoints;
		xi_set_value_i32(datapoint, ArduinoData);
		//Datastream1
		feed.datastreams[1].datapoint_count=1;
		xi_str_copy_untiln(feed.datastreams[1].datastream_id, sizeof(xi_datastream_id1), xi_datastream_id1, '\0' );
		datapoint = (xi_datapoint_t*)&feed.datastreams[1].datapoints;
		xi_set_value_i32(datapoint, 0xff-value);
		xi_feed_update(xi_context, &feed);
		//printf( "err: %d - %s\n", ( int ) xi_get_last_error(), xi_get_error_string( xi_get_last_error() ) ); fflush(stdout);

		//---------------------------------------------- Feed Get
		

		value++;
	}
	
	// destroy the context cause we don't need it anymore
	xi_delete_context( xi_context );
}


#define I2C_ID_PCF8574A 0x38
void* Thread4(void *data)
{
	int fd;
	fd=wiringPiI2CSetup(I2C_ID_PCF8574A);
	
	for (;;)
	{
		wiringPiI2CWrite (fd, 0x55);
		//printf("Cnt_sSDA=%d, Cnt_sSCL=%d\n", Cnt_sSDA, Cnt_sSCL); //fflush(stdout);
		usleep(500*1000);
		wiringPiI2CWrite (fd, 0xaa);
		//printf("Cnt_sSDA=%d, Cnt_sSCL=%d\n", Cnt_sSDA, Cnt_sSCL); //fflush(stdout);
		usleep(500*1000);
	}
}




void* Thread5(void *data)
{
	int fd ;

	char RxBuf, IdxRxBuf;
	unsigned int Rxd=0;
  	if ((fd = serialOpen ("/dev/ttyACM0", 115200)) >= 0){
		for (;;){
			while(serialDataAvail (fd)){
				RxBuf=(char)serialGetchar(fd);
				if(RxBuf=='~'){
					IdxRxBuf=0;
					Rxd=0;
				}
				else{
					Rxd=Rxd | (((RxBuf<='9') ? (RxBuf-'0') : (RxBuf-'A'+10)) * (0x1000>>(IdxRxBuf*4)));
					IdxRxBuf++;
				}

				if(IdxRxBuf >= 4){
					//printf("%d\n", Rxd);fflush(stdout);
					ArduinoData=Rxd;
				}
				//printf("%c", RxBuf);fflush(stdout);
			}
			usleep(1);
		}
  	}
	else{
		fprintf (stderr, "Unable to open serial device: %s\n", strerror (errno)) ;
	}
	serialClose(fd);
}





void ISR_sSDA(void)
{
	Cnt_sSDA++;
//	printf("D");fflush(stdout);
/*
	if(digitalRead(InSig)){
//		wiringPiISR (InSig, INT_EDGE_FALLING, &ISR_GPIO16);
		pinMode (TestSig, OUTPUT) ;
	}
	else{
//		wiringPiISR (InSig, INT_EDGE_RISING, &ISR_GPIO16);
		pinMode (TestSig, INPUT) ;
	}
*/
}


void ISR_sSCL(void)
{
	Cnt_sSCL++;
//	printf("C");fflush(stdout);
/*
	if(digitalRead(InSig)){
//		wiringPiISR (InSig, INT_EDGE_FALLING, &ISR_GPIO16);
		pinMode (TestSig, OUTPUT) ;
	}
	else{
//		wiringPiISR (InSig, INT_EDGE_RISING, &ISR_GPIO16);
		pinMode (TestSig, INPUT) ;
	}
*/
}


void PlayMP3(void)
{
	system ("mpg321 -g 100 /root/MkWorks/DongDong3/Test.mp3"); 
	//system ("/root/MkWorks/DongDong3/test.sh");
}

void setup (void)
{
	pthread_t p_thread[4];
	
	wiringPiSetup();
	pinMode (LED, OUTPUT) ;
	pinMode (sSDA, INPUT) ;
	pinMode (sSCL, INPUT) ;
	digitalWrite (LED, 0) ;	

	wiringPiISR (sSDA, INT_EDGE_BOTH, &ISR_sSDA);
	wiringPiISR (sSCL, INT_EDGE_BOTH, &ISR_sSCL);
	

//	system ("gpio load i2c 100"); //Load I2C Device Driver Module as 100Kbps

	sem_init(&Semaphore, 0, 0);
	pthread_create(&p_thread[0], NULL, Thread1, NULL);
	pthread_create(&p_thread[1], NULL, Thread2, NULL);
	pthread_create(&p_thread[2], NULL, Thread3, NULL);
	pthread_create(&p_thread[3], NULL, Thread4, NULL);
	pthread_create(&p_thread[4], NULL, Thread5, NULL);
	
	pthread_detach(p_thread[0]);
	pthread_detach(p_thread[1]); 
	pthread_detach(p_thread[2]);
	pthread_detach(p_thread[3]);
	pthread_detach(p_thread[4]);
}

int main (void)
{
	printf("\n Start...\n"); fflush(stdout);

	(void)piHiPri (10);

	setup();
/*
	if(fork() == 0)
	{
		PlayMP3();
		return -1;	
	}
*/	
	for (;;)
	{
//		printf("Cnt_sSDA=%d, Cnt_sSCL=%d\n", Cnt_sSDA, Cnt_sSCL); //fflush(stdout);
		sleep(1);
		//delay (1000);
	}
	
	pause();
	printf("\n End...\n"); fflush(stdout);
	return 0 ;
}
